﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using GAIQ;

namespace DCIMAP.GANS.GeneticAlgorithms.Legacy
{
    /// <summary>
    /// Evaluator for solving a SET-PARTITION problem.
    /// It works with BooleanArrayGenes gene type.
    /// </summary>
    [Serializable]
    class IQEvaluator : GeneEvaluator
    {
        /// <summary>
        /// Последовательность, в которой надо найти закономерность
        /// </summary>
        private readonly int[] sequence;
        private readonly int maxint;
        private bool flag;

        /// <summary>
        /// Передаем последовательность
        /// </summary>
        public IQEvaluator(int[] sequence)
        {
            this.sequence = sequence;
            this.maxint = System.Int32.MaxValue;
        }

        /// <inheritdoc/>
        public override double Evaluate(Gene gene)
        {
            StringArrayGene g = (StringArrayGene)gene;
            flag = args(g); //отвечает за количество аргументов в функции:true ->2; false ->1
            int n = sequence.Length;
            int max = 0;
            if (flag)
                n--;
            for (int i = 0; i < n-1; i++)
            {
                int var;
                if(flag)
                    var = Math.Abs(sequence[i+2] - count(g, sequence[i], sequence[i + 1]));
                else
                    var = Math.Abs(sequence[i+1] - count(g, sequence[i], sequence[i]));
                if (var > max)
                    max = var;
            }
            if (max != 0)
                return 1.0 / (2 + max);
            return (1.0 / 2 + 1.0 / (1 + g.StringCode.Length));
        }

        private bool args(StringArrayGene g)
        {
            int n = g.StringCode.Length;
            bool f1 = false, f2 = false;
            for (int i = 0; i < n; i++)
            {
                switch (g.StringCode[i])
                {
                    case "x":
                        f1 = true;
                        break;
                    case "y":
                        f2 = true;
                        break;
                }
                if (f1 && f2)
                    return true;
            }
            return false;
        }

        public int count(StringArrayGene g, int arg1, int arg2)
        {
            Stack stack = new Stack();
            int n = g.StringCode.Length;
            int rez = maxint;
            for (int i = 0; i < n; i++)
            {
                switch (g.StringCode[i])
                {
                    case "x":
                        stack.Push(arg1);
                        break;
                    case "y":
                        stack.Push(arg2);
                        break;
                   /* case "1":
                        stack.Push(1);
                        break;*/
                    default:
                        if (!ListOp.isOp(g.StringCode[i]))
                            stack.Push(Convert.ToInt32(g.StringCode[i]));
                        else
                        {
                            int b = (int)stack.Pop();
                            int a = (int)stack.Pop();
                            if (g.StringCode[i].Equals("/") && (b == 0 || (a % b) != 0))
                                return maxint;
                            rez = ListOp.getOp(g.StringCode[i]).eval(a, b);
                            stack.Push(rez);
                        }
                        break;
                }
            }
            return rez;
        }
    }
}